package per.qiao;

import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.codeInsight.highlighting.*;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.find.FindManager;
import com.intellij.find.findUsages.FindUsagesHandler;
import com.intellij.find.findUsages.FindUsagesManager;
import com.intellij.find.impl.FindManagerImpl;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.editor.markup.HighlighterLayer;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;


/**
 * Created by Rammer on 06/02/2017.
 */
public class MultiHighlightHandler {

    /**
     * {@link com.intellij.codeInsight.highlighting.HighlightUsagesHandler#invoke(Project, Editor,
     * PsiFile)}
     *
     * {@link com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPass#doCollectInformation(ProgressIndicator)}
     */
    public static void invoke(@NotNull Project project, @NotNull Editor editor,
                              @NotNull PsiFile file, boolean isClear) {
        PsiDocumentManager.getInstance(project).commitAllDocuments();

        if (handleCustomUsage(editor, file)) {
            return;
        }

        DumbService.getInstance(project).withAlternativeResolveEnabled(() -> {
            findTarget(project, editor, file, isClear);
            /*if (!findTarget(project, editor, file)) {
                handleNoUsageTargets(file, editor, project, null);
            }*/
               // handleNoUsageTargets(file, editor, project);
        });
    }


    private static boolean handleCustomUsage(@NotNull Editor editor, @NotNull PsiFile file) {
        final HighlightUsagesHandlerBase handler =
                HighlightUsagesHandler.createCustomHandler(editor, file);

        if (handler == null) {
            return false;
        }

        final String featureId = handler.getFeatureId();
        if (featureId != null) {
            FeatureUsageTracker.getInstance().triggerFeatureUsed(featureId);
        }

        final List targets = handler.getTargets();
        if (targets == null) {
            return false;
        }

        try {
            handler.highlightUsages();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    private static boolean findTarget(@NotNull Project project, @NotNull Editor editor,
                                      @NotNull PsiFile file, boolean isClear) {
        PsiJavaFile javaFile = (PsiJavaFile) file;
        PsiClass psiClass = javaFile.getClasses()[0];
        PsiMethod[] methods = psiClass.getMethods();
        for (PsiMethod method : methods) {
            PsiAnnotation[] annotations = method.getAnnotations();
            for (PsiAnnotation annotation :annotations) {
                if (!"java.lang.Deprecated".equals(annotation.getQualifiedName())) {
                    continue;
                }
                handleNoUsageTargets(file, editor, project, isClear);

                // 高亮个方法名
               //highlightPsiElement(project, method, editor, file, false);

               /* UsageTarget[] usageTargets = UsageTargetUtil.findUsageTargets(method);
                for (UsageTarget target : usageTargets) {
                    //把方法名给高亮了
                    target.highlightUsages(file, editor, isClearHighlights(editor));
                }*/
            }
        }
        return true;
    }

    private static boolean isClearHighlights(@NotNull Editor editor) {
        if (editor instanceof EditorWindow) {
            editor = ((EditorWindow) editor).getDelegate();
        }

        final Project project = editor.getProject();
        if (project == null) {
            //Log.error("isClearHighlights: editor.getProject() == null");
            return false;
        }

        int caretOffset = editor.getCaretModel().getOffset();
        final RangeHighlighter[] highlighters =
                ((HighlightManagerImpl) HighlightManager.getInstance(project)).getHighlighters(
                        editor);
        for (RangeHighlighter highlighter : highlighters) {
            if (TextRange.create(highlighter).grown(1).contains(caretOffset)) {
                return true;
            }
        }

        return false;
    }

    private static void clearHighlights(Editor editor, HighlightManager highlightManager,
                                        List<TextRange> toRemoves) {
        if (editor instanceof EditorWindow) {
            editor = ((EditorWindow) editor).getDelegate();
        }

        RangeHighlighter[] highlighters =
                ((HighlightManagerImpl) highlightManager).getHighlighters(editor);

        Arrays.sort(highlighters, (o1, o2) -> o1.getStartOffset() - o2.getStartOffset());
        Collections.sort(toRemoves, (o1, o2) -> o1.getStartOffset() - o2.getStartOffset());

        int i = 0;
        int j = 0;
        while (i < highlighters.length && j < toRemoves.size()) {
            RangeHighlighter highlighter = highlighters[i];
            final TextAttributes ta = highlighter.getTextAttributes();
            final TextRange textRange = TextRange.create(highlighter);
            final TextRange toRemove = toRemoves.get(j);
            if (ta != null && ta instanceof NamedTextAttr // wrap
                    && highlighter.getLayer() == HighlighterLayer.SELECTION - 1 // wrap
                    && toRemove.equals(textRange)) {
                highlightManager.removeSegmentHighlighter(editor, highlighter);
                i++;
            } else if (toRemove.getStartOffset() > textRange.getEndOffset()) {
                i++;
            } else if (toRemove.getEndOffset() < textRange.getStartOffset()) {
                j++;
            } else {
                i++;
                j++;
            }
        }
    }

    private static void highlight(@NotNull HighlightManager highlightManager,
                                  @NotNull Collection<TextRange> textRanges, @NotNull Editor editor,
                                  @Nullable Collection<RangeHighlighter> holder
    ) {
        final TextAttributes ta = TextAttributesFactory.getInstance().get();
        final Color scrollMarkColor;
        if (ta.getErrorStripeColor() != null) {
            scrollMarkColor = ta.getErrorStripeColor();
        } else if (ta.getBackgroundColor() != null) {
            scrollMarkColor = ta.getBackgroundColor().darker();
        } else {
            scrollMarkColor = null;
        }
        for (TextRange range : textRanges) {
            highlightManager.addOccurrenceHighlight(editor, range.getStartOffset(),
                    range.getEndOffset(), ta, 0, holder, scrollMarkColor);
        }
    }

    /**
     * {@link com.intellij.codeInsight.highlighting.HighlightUsagesHandler#handleNoUsageTargets(PsiFile,
     * Editor, SelectionModel, Project)}
     */
    private static void handleNoUsageTargets(PsiFile file, @NotNull Editor editor,
                                             @NotNull Project project, boolean isClear) {

        List<TextRange> writeRanges = new ArrayList<>();

        final HighlightManager highlightManager = HighlightManager.getInstance(project);

        addUpdatePositionOfMehtod((PsiJavaFile) file, writeRanges);

        // 是否需要清理
        if (isClear) {
            clearHighlights(editor, highlightManager, writeRanges);
            WindowManager.getInstance().getStatusBar(project).setInfo("");
            return;
        }
        ArrayList<RangeHighlighter> highlighters = new ArrayList<>();
        highlight(highlightManager, writeRanges, editor, highlighters);

        return;
    }

    /**
     * 将需要修改的方法添加到writeRanges容器中
     * @param javaFile java文件
     * @param writeRanges
     */
    private static void addUpdatePositionOfMehtod(PsiJavaFile javaFile, List<TextRange> writeRanges) {
        // java文件中的内容 字符串形式
        String fileText = javaFile.getText();
        // 类对象
        PsiClass psiClass = javaFile.getClasses()[0];
        // 方法名
        PsiMethod[] methods = psiClass.getMethods();
        // 遍历到有注解的添加到容器中
        for (PsiMethod method : methods) {
            PsiAnnotation[] annotations = method.getAnnotations();
            for (PsiAnnotation annotation : annotations) {
                if (!"java.lang.Deprecated".equals(annotation.getQualifiedName())) {
                    continue;
                }
                String methodText = method.getText();
                int index = fileText.indexOf(methodText);
                //标记整个方法体的位置(包括注解), 开始位置，结束位置
                 writeRanges.add(new TextRange(index, index + methodText.length()));
            }
        }
    }
}